﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Dedup
{
    public partial class Form1 : Form
    {
        ManualResetEvent completed = new ManualResetEvent(false);
        List<string> exclusionList = new List<string>();
        public Form1()
        {
            InitializeComponent();
            foreach (var item in listBox2.Items)
            {
                exclusionList.Add(item.ToString().ToLowerInvariant());
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            comboBox1.SelectedIndex = 1;
        }

        string fileTypes = string.Empty;
        private void button2_Click(object sender, EventArgs e)
        {
            completed.Reset();
            dupList.Clear();
            dupList2.Clear();
            dataGridView1.Rows.Clear();
            dataGridView1.Columns.Clear();
            label2.Text = "Searching...";
            label1.Text = "";
            fileTypes = comboBox1.SelectedItem.ToString();
            Task t = new Task(Search);
            t.Start();
            //t.Wait();
            dataGridView1.Columns.Add(new DataGridViewLinkColumn());
            dataGridView1.Columns.Add(new DataGridViewCheckBoxColumn());
            dataGridView1.Columns.Add(new DataGridViewLinkColumn());
            dataGridView1.Columns.Add(new DataGridViewCheckBoxColumn());
            //for (int i = 0; i < dupList.Count; i++)
            //    dataGridView1.Rows.Add(dupList[i], false, dupList2[i], false);
            //k = dupList.Count;
            //dataGridView1.Invalidate();
            //label2.Text = dupList.Count + " records found";

            int k = 0, i = 0;
            while (!completed.WaitOne(1000))
            {
                for (i = k; i < dupList.Count; i++)
                    dataGridView1.Rows.Add(dupList[i], false, dupList2[i], false);
                k = i + 1;
                dataGridView1.Invalidate();
                label2.Text = dupList.Count + " records found";
            }
            for (i = k; i < dupList.Count; i++)
                dataGridView1.Rows.Add(dupList[i], false, dupList2[i], false);
            dataGridView1.Invalidate();
            label2.Text = dupList.Count + " records found";
        }
        List<string> dupList = new List<string>();
        List<string> dupList2 = new List<string>();

        private void Search()
        {
            List<string> dupFList = new List<string>();
            List<FileObj> filesList = new List<FileObj>();

            foreach (var item in listBox1.Items)
            {
                foreach (string file in SafeFileEnumerator.EnumerateFiles(item.ToString(), "*" + fileTypes, SearchOption.AllDirectories, exclusionList))
                    filesList.Add(new FileObj(Path.GetFileName(file), file));
            }

            for (int i = 0; i < filesList.Count; i++)
            {
                for (int j = 0; j < filesList.Count; j++)
                    try
                    {
                        if (i != j
                            && filesList[i].file == filesList[j].file
                            && !dupFList.Contains(filesList[i].file)
                            && new FileInfo(filesList[i].filePath).Length == new FileInfo(filesList[j].filePath).Length)
                        {
                            dupList.Add(filesList[i].filePath);
                            dupList2.Add(filesList[j].filePath);
                            dupFList.Add(filesList[i].file);
                        }
                    }
                    catch (PathTooLongException)
                    { }
            }
            completed.Set();            
        }

        private void button3_Click(object sender, EventArgs e)
        {
            DeleteFiles(false);            
        }        

        private void DeleteFiles(bool isPreview)
        {
            double size = 0;
            long count = 0;
            foreach (DataGridViewRow item in dataGridView1.Rows)
            {
                try
                {
                    object obj = item.Cells[2].Value;
                    if (item.Cells[1].Value.ToString() == "True")
                    {
                        size += new FileInfo(item.Cells[0].Value.ToString()).Length;
                        if (!isPreview)
                            File.Delete(item.Cells[0].Value.ToString());
                        count++;
                    }
                    if (item.Cells[3].Value.ToString() == "True")
                    {
                        size += new FileInfo(item.Cells[2].Value.ToString()).Length;
                        if (!isPreview)
                            File.Delete(item.Cells[2].Value.ToString());
                        count++;
                        //MessageBox.Show(item.Cells[2].Value.ToString() + " deleted");
                    }
                }
                catch (FileNotFoundException)
                { }
            }
            if (count > 0)
            {
                double sizeInMB = (double)size / (1024 * 1024);
                if (isPreview)
                    MessageBox.Show(string.Format("Total files to be deleted: {0}\nTotal space to be saved: {1} MB", count, sizeInMB.ToString("0.##")));
                else
                    MessageBox.Show(string.Format("Total files deleted: {0}\nTotal space saved: {1} MB", count, sizeInMB.ToString("0.##")));
            }
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            foreach (DataGridViewRow item in dataGridView1.Rows)
            {
                if (checkBox1.Checked)
                    item.Cells[1].Value = true;
                else
                    item.Cells[1].Value = false;
            }
        }
        
        private void button1_Click(object sender, EventArgs e)
        {
            folderBrowserDialog1.ShowDialog();
            textBox1.Text = folderBrowserDialog1.SelectedPath;
        }

        private void checkBox2_CheckedChanged_1(object sender, EventArgs e)
        {
            foreach (DataGridViewRow item in dataGridView1.Rows)
            {
                if (checkBox2.Checked)
                    item.Cells[3].Value = true;
                else
                    item.Cells[3].Value = false;
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            DeleteFiles(true);
        }

        private void button5_Click(object sender, EventArgs e)
        {
            pictureBox1.ImageLocation = @"D:\DP\MyData\Aarav\ss.jpg";
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;

        }

        private void pictureBox1_Click(object sender, EventArgs e)
        {

        }

        private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex == 0 || e.ColumnIndex == 2)
            {
                pictureBox1.ImageLocation = (((DataGridView)(sender)).CurrentCell).Value.ToString();
                pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
            }
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void button5_Click_1(object sender, EventArgs e)
        {
            if (!listBox1.Items.Contains(textBox1.Text))
                listBox1.Items.Add(textBox1.Text);
        }

        private void button6_Click(object sender, EventArgs e)
        {

        }

        private void listBox2_SelectedIndexChanged(object sender, EventArgs e)
        {
            
        }
    }
    public class FileObj
    {
        public string file;
        public string filePath;
        public FileObj(string f, string p)
        {
            file = f;
            filePath = p;
        }
    }

    public class DataGridGroupObject
    {
        public string name { get; set; } // this will be match name column
        public DataGridViewCheckBoxCell action { get; set; }
    }

    public static class SafeFileEnumerator
    {
        public static IEnumerable<string> EnumerateDirectories(string parentDirectory, string searchPattern, SearchOption searchOpt,
            List<string> exclusions)
        {
            try
            {
                var directories = Enumerable.Empty<string>();
                if (exclusions.Contains(parentDirectory))
                    return directories;
                if (searchOpt == SearchOption.AllDirectories)
                {
                    directories = Directory.EnumerateDirectories(parentDirectory)
                        .SelectMany(x => EnumerateDirectories(x, searchPattern, searchOpt, exclusions));
                }
                return directories.Concat(Directory.EnumerateDirectories(parentDirectory, searchPattern));
            }
            catch (UnauthorizedAccessException ex)
            {
                return Enumerable.Empty<string>();
            }
        }

        public static IEnumerable<string> EnumerateFiles(string path, string searchPattern, SearchOption searchOpt, List<string> exc)
        {
            try
            {
                var dirFiles = Enumerable.Empty<string>();
                var dirName = Path.GetFileName(path);
                if (exc.Contains(path.ToLowerInvariant()) || exc.Where((x) => x.StartsWith(path.ToLowerInvariant() + "\\")).ToList().Count > 0 || 
                    (!string.IsNullOrWhiteSpace(dirName) && dirName.StartsWith("$"))) 
                    return dirFiles;
                if (searchOpt == SearchOption.AllDirectories)
                {
                    dirFiles = Directory.EnumerateDirectories(path)
                                        .SelectMany(x => EnumerateFiles(x, searchPattern, searchOpt, exc));
                }
                return dirFiles.Concat(Directory.EnumerateFiles(path, searchPattern));
            }
            catch (UnauthorizedAccessException ex)
            {
                return Enumerable.Empty<string>();
            }
            catch (PathTooLongException ex)
            {
                return Enumerable.Empty<string>();
            }
        }
    }
}
